#include "cc_malloc.h"
#include "cc_limits.h"
#include "cc_math.h"

int __cdecl cc_abs(int n)
{
	return (n < 0 ? -n : n);
}

long __cdecl cc_labs(long n)
{
	return (n < 0L ? -n : n);
}

long long __cdecl cc_llabs(long long n)
{
	return (n < 0 ? -n : n);
}

double __cdecl cc_fabs( double d )
{
	return (d < 0 ? -d : d);
}

double __cdecl cc_sqrt( double d )
{
	double x1 = d / 2;
	double x0;
	do
	{
		x0 = x1;
		x1 = (double)(0.5 * (x0 + d / x0));
	}while(cc_fabs(x1 - x0) > 1e-5);
	return x1;
}

// nth root (n > 0 )
double __cdecl cc_extraction_root( double d, int n )
{
	double x0 = 1.0;
	double x1;
	do 
	{
		x1 = x0;
		x0 -= (cc_fractional_power(x0, n) - d) / (n * cc_fractional_power(x0, n - 1));
	} while (cc_fabs(x0 - x1) > 1e-8);
	return x1;
}

double __cdecl cc_pow_v2(double base, double exp)
{
	long long num;
	long long den;
	double involution;
	double result;
	cc_decimal_to_fraction(exp, &num, &den);
	involution = cc_fractional_power(base, num);
	result = cc_extraction_root(involution, den);
	return result;
}

unsigned long long __cdecl cc_factorial( size_t n )
{
	if(n <= 1)
	{
		return 1;
	}
	else
	{
		return n * cc_factorial(n - 1);
	}
}

unsigned long long __cdecl cc_factorial_ex( 
	size_t n 
	)
{
	unsigned long long rst = 1;
	if(n <= 1)
		return 1;

	while(n >= 2)
	{
		rst *= n;
		--n;
	}
	return rst;
}

long double __cdecl cc_integral_power( long base, long n )
{
	long double result = (long double)(base);
	if(n == 0)
	{
		return 1;
	}
	else if(n == 1)
	{
		return result;
	}
	else
	{
		unsigned long i;
		long exponent = n < 0 ? -n : n;
		for(i = 0; i < exponent - 1; ++i)
		{
			result *= base;
		}
		return n < 0 ? 1 / result : result;
	}
}
long double __cdecl cc_fractional_power( long double base, long n )
{
	long double result = (long double)(base);
	if(n == 0)
	{
		return 1;
	}
	else if(n == 1)
	{
		return result;
	}
	else
	{
		unsigned long i;
		long exponent = n < 0 ? -n : n;
		for(i = 0; i < exponent - 1; ++i)
		{
			result *= base;
		}
		return n < 0 ? 1 / result : result;
	}
}

// 
// cc_sin(x)=x-x^3/3!+x^5/5!-...+(-1)^(m-1)*x^(2m-1)/(2m-1)!
long double __cdecl cc_sin( long double radian )
{
	long double result = .0;
	int i;
	for( i = 1; i < 10; ++i)
	{
		result += cc_integral_power(-1,i - 1) 
			* cc_fractional_power(radian, 2 * i - 1)
			/ cc_factorial(2 * i - 1);
	}
	return result;
}

//cc_cos(z)=1-z^2/(2!)+z^4/(4!)-z^6/(6!)+...+(-1)^(m-1)*z^(2*(m-1))/(2*(m-1))!
long double __cdecl cc_cos( long double radian )
{
	long double result = .0;
	int i;
	for(i = 1; i < 10; ++i)
	{
		result += cc_integral_power(-1, i - 1)
			* cc_fractional_power(radian, 2 * i - 2)
			/ cc_factorial(2 * i - 2);
	}
	return result;
}

long double __cdecl cc_tan( long double radian )
{
	return cc_sin(radian) / cc_cos(radian);
}

int __cdecl cc_checked_add( int a, int b, int *isOverflowed )
{
	*isOverflowed = 0;
	if ((a > 0 && b > 0 && a + b <= 0) 
	 || (a < 0 && b < 0 && a + b >= 0))
	{		// overflow occurs
		*isOverflowed = 1;
		return INT_MIN;
	}	

	return (a + b);
}

double __cdecl cc_ceil( 
	double num 
	)
{
	long temp = (long)num;
	if(temp == num)
		return (double)temp;

	return ((num < 0) ? (long)num : ((long)num + 1));
}

double __cdecl cc_floor( 
	double num 
	)
{
	long temp = (long)num;
	if(temp == num)
		return (double)temp;

	return ((num < 0) ? ((long)num - 1) : (long)num);
}

// greatest common divisor
long long __cdecl cc_gcd( long long a, long long b )
{
	if (a == 0)
	{
		return b;
	}
	if (b == 0)
	{
		return a;
	}
	return cc_gcd(max(a, b) - min(a, b), min(a, b));
}

// get the least common multiple
long long __cdecl cc_lcm(
	long long a,
	long long b
);

// split a floating point number into integer part and fraction part
double __cdecl cc_modf(
	double d,
	double *i
	)
{
//	double temp = d;
	long long ll = (long long)d;
//	*(long long*)&temp &= 0xFFF0000000000000LL; 
	*i = (double)ll;;
	return d - ll;
}

// truncate to make the number of  the digits after the decimal point to 2
double __cdecl cc_two_digits_after_decimal_point(
	double d
	)
{
	double temp = d;
	long long ll = (long long)((temp + 0.005) * 100);
	temp = ll;
	temp /= 100;
	return temp;
}

// transform decimal to fraction
void __cdecl cc_decimal_to_fraction(
	double d,
	long long *numerator,
	long long *denominator
	)
{
	double temp;
	long long nu;//numerator
	long long de;//denominator
	temp = cc_two_digits_after_decimal_point(d);
	nu = temp * 100;
	de = 100;
	cc_fraction_to_simplest(&nu, &de);
	*numerator = nu;
	*denominator = de;
	return;
}

// make the fraction the simplest form
void __cdecl cc_fraction_to_simplest(
	long long *numerator,
	long long *denominator)
{
	long long gcd = cc_gcd(numerator, denominator);
	*numerator /= gcd;
	*denominator /= gcd;
	return;
}

// e^x=1+x+x^2/(2!)+x^3/(3!)+...+x^n/(n!)     
double __cdecl cc_exp(
	double d
	)
{
	double result = 1.0;
	double temp = d;
	int i = 1;
	while (i < 100)
	{
		result += temp;
		++i;
		temp *= d;
		temp /= i;
	}
	return result;
}

// ln(1+x)=x-x^2/2+x^3/3-...+(-1)^(n-1)*x^n/n     -1<x<=1
double __cdecl cc_log(
	double d
	)
{
	int i = 1;
	int j = 0;
	double result = .0;
	double temp = d - 1;
	if (d == 1)
	{
		return 0;
	}
	
	/*else if (d < 1)
	{
		return -1 * cc_log(1 / d);
	}
	*/
	else if (d <= 2)
	{
		while(i < 300)
		{
			result += temp;
			++i;
			temp = cc_integral_power(-1, i - 1) * cc_fractional_power(d - 1, i) / i;
		}
		return result;
	}
	else
	{
		while (d > 2)
		{
			d /= 2;
			++j;
		}
		return j * LN2 + cc_log(d);
	}
}

// log10(x)=log(x)/log(10)
double __cdecl cc_log10(
	double d
	)
{
	return cc_log(d) / cc_log(10);
}

// pow(m,n)=e^(n*log(m))=exp(n*log(m)   m>0
double __cdecl cc_pow(
	double m,
	double n)
{
	double integer;
	if (X_IS_EQUAL_TO_Y(m, 0))
	{
		if (n >= 0.0)
		{
			return 1;
		}
		else
		{
			return -1;
		}
	} 
	else if(m < 0)
	{
		if (!X_IS_EQUAL_TO_Y(cc_modf(n, &integer), 0))
		{
			return -1;
		}
		
		
	}
	
	return cc_exp(n * cc_log(m));
}

// pow10(x)=pow(10,x)
double __cdecl cc_pow10(
	double d
	)
{
	return cc_pow(10, d);
}

int __cdecl cc_isPrime( 
	unsigned n 
	)
{
	int i = 2;
	int nSqrt;

	if(n < 2)
		return 0;
	if(n % 2 == 0)
		return 0;

	nSqrt = (int)cc_sqrt(n);
	for (; i <= nSqrt; ++i)
	{
		if(n % i == 0)
			return 0;
	}

	return 1;
}

long long __cdecl cc_lcm( 
	long long a, 
	long long b 
	)
{
	return (a * b / cc_gcd(a, b));
}



